﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace MappitLib {
    public partial class TilesetEditor : UserControl {
        /****************************************************************
         * Class defaults
         ****************************************************************/
        public static Color default_highlighted_tile_color = Color.Green;
        public static int default_highlighted_tile_alpha = 128;
        public static Color default_tile_cursor_color = Color.Yellow;
        public static int default_tile_cursor_alpha = 255;
        public static int default_tile_cursor_thickness = 2;
        /************************************************************
         * Members
         ************************************************************/
        private Tileset tileset_ = new Tileset();
        //private Rectangle tile_highlighted_rect_ = new Rectangle();
        //private Rectangle tile_cursor_rect_ = new Rectangle();
        private Point highlighted_tile_ = new Point();
        private Point selected_tile_ = new Point();
        private int zoom_factor_ = 1;
        /************************************************************
         * Properties
         ************************************************************/
        public Tileset Tileset {
            get { return tileset_; }
            set { SetTileset(value); }
        }
        public int ZoomFactor {
            get {
                return zoom_factor_;
            }
            set {
                zoom_factor_ = value;
            }
        }
        public Point SelectedTile {
            get { return selected_tile_; }
        }
        public string Filename {
            get { return tileset_.Pathname; }
        }
        /************************************************************
         * Events
         ************************************************************/
        private void imagePanel_MouseMove(object sender, MouseEventArgs e) {
            SetHighlightedTile(e.Location);
        }

        private void imagePanel_Paint(object sender, PaintEventArgs e) {
            DrawTileHighlight(e.Graphics);
            DrawTileCursor(e.Graphics);
        }

        private void imagePanel_MouseLeave(object sender, EventArgs e) {
            // invalidate the current highlighted tile
            imagePanel.Invalidate(GetTileRect(highlighted_tile_));
            // de-highlight the tile
            highlighted_tile_ = new Point(-1, -1);
        }

        private void imagePanel_MouseClick(object sender, MouseEventArgs e) {
            this.Focus();
            SetSelectedTile(e.Location);
        }

        private void scrollPanel_MouseWheel(object sender, MouseEventArgs e) {
            MouseScroll(e.Delta);
        }

        /************************************************************
         * Methods
         ************************************************************/
        /*! Constructor. 
         */
        public TilesetEditor() {
            InitializeComponent();
            this.MouseWheel += new MouseEventHandler(scrollPanel_MouseWheel);
        }
        /*! Load tileset from file.
         */
        public void LoadFile(string filename) {
            tileset_.LoadBitmap(filename);
            UpdateImagePanel();
            UpdateStatusBar();
            // redraw the whole control
            Refresh();
        }

        private void UpdateImagePanel() {
            imagePanel.BackgroundImage = tileset_.Bitmap;
            if (tileset_.Bitmap != null)
                imagePanel.Size = tileset_.Bitmap.Size;
        }

        private void UpdateStatusBar() {
            statusFilename.Text = Path.GetFileName(Filename);
            statusTilesetSize.Text =
                tileset_.Width.ToString() +
                "x" +
                tileset_.Height.ToString();
        }
        public void SetTileset(Tileset tileset) {
            tileset_ = tileset;
            UpdateStatusBar();
            UpdateImagePanel();
        }


        private void SetHighlightedTile(Point mouse_position) {
            // determine which tile the mouse is over
            Point new_position = GetTilePos(mouse_position);
            // if the tile is the same as previously selected, don't do anything
            if (new_position == highlighted_tile_) {
                return;
            }
            // invalidate the current highlighted tile area
            imagePanel.Invalidate(GetTileRect(highlighted_tile_));
            // set the new highlighted tile
            highlighted_tile_ = new_position;
            // get the rectangular area that the tile occupies
            Rectangle highlighted_rect = GetTileRect(highlighted_tile_);
            // invalidate the new highlighted tile area
            imagePanel.Invalidate(highlighted_rect);
            // repaint the control
            Update();
        }

        private void DrawTileHighlight(Graphics gfx) {
            using (Brush b = new SolidBrush(
                Color.FromArgb(default_highlighted_tile_alpha,
                default_highlighted_tile_color))) {
                gfx.FillRectangle(b, GetTileRect(highlighted_tile_));
            }
        }

        private void DrawTileCursor(Graphics gfx) {
            Rectangle cursor_area = GetCursorRect(selected_tile_);
            using (Pen p = new Pen(Color.FromArgb(default_tile_cursor_alpha,
                default_tile_cursor_color), default_tile_cursor_thickness)) {
                p.Alignment = System.Drawing.Drawing2D.PenAlignment.Inset;
                gfx.DrawRectangle(p, cursor_area);
            }
        }

        private Rectangle GetCursorRect(Point tile_location) {
            Rectangle tile_area = GetTileRect(tile_location);
            return new Rectangle(
                            tile_area.X - default_tile_cursor_thickness,
                            tile_area.Y - default_tile_cursor_thickness,
                            tile_area.Size.Width + (default_tile_cursor_thickness * 2),
                            tile_area.Size.Height + (default_tile_cursor_thickness * 2));
        }

        private Rectangle GetTileRect(Point tile_position) {
            return tileset_.GetTileRect(tile_position);
        }
        private Point GetTilePos(Point pixel_pos) {
            return tileset_.GetTilePos(pixel_pos);
        }

        private void MouseScroll(int delta) {
            Point scrollPosition = scrollPanel.AutoScrollPosition;
            // zoom?
            if (Control.ModifierKeys == Keys.Control) {
                if (delta < 0) {
                    ++ZoomFactor;
                } else {
                    --ZoomFactor;
                }
            }
                // scroll horizontally?
            else if (Control.ModifierKeys == Keys.Shift) {
                int x = Math.Abs(scrollPosition.X);
                x += delta < 0 ? tileset_.TileWidth : tileset_.TileWidth * -1;
                scrollPosition.X = x;
                scrollPosition.Y = Math.Abs(scrollPosition.Y);
            }
                // scroll vertically
            else {
                int y = Math.Abs(scrollPosition.Y);
                y += delta < 0 ? tileset_.TileHeight : tileset_.TileHeight * -1;
                scrollPosition.Y = y;
                scrollPosition.X = Math.Abs(scrollPosition.X);
            }
            scrollPanel.AutoScrollPosition = scrollPosition;
        }

        private void SetSelectedTile(Point mouse_location) {
            // invalidate the current cursor area
            imagePanel.Invalidate(GetCursorRect(selected_tile_));
            // determine which tile the mouse is over
            selected_tile_ = GetTilePos(mouse_location);
            // invalidate the cursor area
            imagePanel.Invalidate(GetCursorRect(selected_tile_));
        }

    }
}
